Beginning OOPs
Volume Number: 7
Issue Number: 8
Column Tag: Beginning OOPs
Object Programming With TCL 
By John Lengyel, St. Louis, MO
[John Lengyel is a software engineer for Digital Systems Consultants of St.
Louis, Missouri. He is currently developing applications on VAX/VMS and Apollo/Unix
platforms. He is looking for Macintosh software development opportunities.]
The Objective
Over the past several years numerous articles have appeared in MacTutor
espousing the virtues of MacApp. Not being a Macintosh programmer by profession and
already owning and enjoying THINK Pascal and THINK C, I managed to suppress my
desire to purchase MacApp. So when my THINK C 4.0 upgrade arrived I wanted to
immediately dig into its object-oriented capabilities.
After reading the well written manual discussing object-oriented programming
and the THINK Class Library (THINK C’s version of MacApp) and looking over the
sample projects provided with the upgrade I thought it would be a good idea to do one or
two MacApp to THINK Class Library (TCL) conversions before jumping off on my own.
The first program I converted is the topic of this article. The program is based upon a
similar program that was written by Larry Rosenstein and presented in the December,
1986 issue of MacTutor titled “Dots Game Shows MacApp”.
TCL and MacApp
At this point, I considered writing the “What is TCL” section of the article. But
anyone who has read or can read past articles on MacApp will have a very good idea of
what TCL is all about. While converting Dots to TCL, the similarity of TCL to MacApp
became increasingly noticeable.
For example, in the MacApp version of Dots, the classes requiring redefinition
are TApplication, TDocument, TView and TCommand. In the TCL version they are
respectively CApplication, CDocument, CView (actually subclasses of CView are
redefined) and CMouseTask (similar to MacApp’s TCommand). The functionality
provided by these corresponding classes is nearly identical. This similarity in name
and function also extends, to a slightly lesser degree, down into the method level.
Studying MacApp articles and code should be helpful to anyone trying to learn
how to write programs in TCL. As an additional TCL specific reference, an overview of
TCL was provided by Alastair Dallas in the October, 1989 issue of MacTutor. Rather
than restating what these people have said about MacApp and TCL I will concentrate my
efforts on the classes that needed to be redefined for Dots and in particular on their
overridden methods.
About Dots...
For those of you who while in high school actually studied during study hall and
do not know how to play Dots, here is a description of the game. Dots is played on a
matrix of dots. Players take turns drawing lines connecting adjacent dots. When a
player draws a line that completes a square in the matrix, that player is awarded the
square. A mark is placed in the square to indicate player ownership. The player
completing the square may then take another turn. The game ends when all lines in the
matrix are drawn. The player awarded the most squares wins the game.
In the TCL version of Dots, which has essentially the same design as its MacApp
counterpart, the game is played in a window. The number of squares awarded each
player is displayed in the top portion of the window. These numbers are hereafter
referred to as the player’s scores. The dot matrix over which the game is played is
displayed in the bottom portion of the window and is scrollable. Lines between adjacent
dots are drawn with mouse clicks. When a square is completed, a graphic pattern
associated with the moving player is used to fill an awarded square to indicate that
player’s ownership of the square. The pattern is also used to display a frame around the
appropriate player’s score. See Figure 1 for a view of the window used in Dots. As for
as the playing of Dots, a correction to the original version was made so that when a
player completes a square it is still that player’s turn.
Figure 1. Views of Dots' Document
Many useful features are exhibited in the Dots program. A multi-view window
that can be scrolled, auto-scrolled, resized, zoomed and printed. Support for the
undoing and redoing of moves. Multifinder compatibility and desk accessory support.
Games can be saved and restored. Multiple windows can be opened and hence games
played. All this and more in a fairly small amount of new, Dot specific code thanks to
TCL.
Table 1 shows the five TCL classes that were redefined for Dots. These five
subclasses and the “main” routine comprise all of the new code that was written for
Dots. All other functionality is provided by the standard TCL code. The rest of this
article will discuss each of the redefined classes and “main”.
TCL Subclass Abridged Description
CApplication cDotsApp Supervises program
CDocument cDotsDoc Manages window and its data
CPane cScorePane Displays scores
CPanorama cDotsPane Displays dot matrix
CMouseTask cDotsTask Handles mouse clicks in matrix
Table 1: TCL Redefines
Source Descriptions
The source files for Dots are organized in the manner recommended in the THINK
C manual. Dots subclasses are defined in a “.h” header file and their methods in a “.c”
file each having the name of the class. As an example, the subclass cDotsApp’s
associated source files are cDotsApp.c and cDotsApp.h. I prefixed the Dots subclasses
with a lower case “c” in order to distinguish them from the standard TCL classes which
all start with an upper case “C”. There does not appear to be a standard for prefixing
the names of class methods or variables in TCL. For class variables I followed the
MacApp practice of preceding the variable name with a lower case “f”. As for class
methods, standard TCL methods start with an upper case letter while Dot specific
methods start in lower case.
The resources used in Dots were copied from the Starter Project supplied by
THINK. A few modifications and additions were then made. A new string was added to
STR# “Common” to supply text for displaying the “About...” alert. The “General”
ALRT and DITL which are used to display the “About...” were then enlarged to
accommodate the text. A DITL and DLOG were added to display a “Press CMD-. to stop
printing” message. A WIND resource was modified for the document window. Finally,
the string “Move” was added to STR# “Task Names”. This string is used by TCL to
display the proper undo/redo command in the edit menu (“Undo Move” or “Redo
Move”).
Main
The main routine when using TCL is rather trivial. It creates an application
object and sends it an initialization message. Main then tells the application to start
running. Finally, when the application finishes running, Main sends an exit message to
the application. Exit() gives the application a last chance to clean up before the
application terminates. For instance, temporary files may need to be deleted. Dots does
not do anything in the Exit() routine. It was left in for illustrative purposes. All very
neat, very orderly. Enough said.
cDotsApp::CApplication
Only one application is created for the entire project. As previously stated, the
Main routine of the project creates the application object, sends the application an
initialization request and then tells the application to begin running. While running,
the application directs the processing of events, gives MultiFinder support, takes some
wrinkles out of memory management, updates menus, handles DAs and is also capable of
handling some of the basic File and Edit menu commands. All of this runtime support is
provided in Dots by the standard TCL code.
To understand program flow using TCL it is important to know about the chain of
command. A chain of command is used to determine which object handles a direct
command. A direct command is a request that an object perform some action. They
usually come about from menu selections. Direct commands that cannot be handled by
an object move up the chain of command. The application is at the top of the chain of
command. By the time the application receives the command it has been passed on by
the views and the document. If the application does not handle the command, the
command will not be handled. A chain of command for Dots is depicted in Figure 2.
Figure 2. The Chain of Command in Dots
The application’s inherited initialization method must be overridden. The Dots
override for this method calls the inherited application’s initialization method. This
must always be done because the inherited method initializes the Macintosh Toolbox, sets
up menus, initializes application specific TCL globals and does a host of other very
helpful but tedious things. The Dots application initialization method also sets up two
global variables each of which are the patterns associated with a particular player. The
use of these patterns is discussed in the cDotsPane and cScorePane sections of this
article. These are application globals because they apply to all games being played and
are not game dependent.
The application method SetUpFileParameters() was overridden in order to
identify the types of files the Dots application recognizes. These types are used for the
Macintosh Toolbox Standard File routines when opening a file. The application method
DoCommand() was overridden so that a simple “About” alert could be posted when the
“About Dots...” command was selected from the Apple menu. Unlike MacApp, TCL does
not support an inherent about box. The application methods CreateDocument() and
OpenDocument() were overridden so that Dots documents could be created whenever a
“New...” or “Open...” was chosen from the File menu.
cDotsDoc::CDocument
The document associates a window with the data that is to be displayed in the
window. The data contained in the document is displayed to the user in the window and
may be stored on disk as a file. A subclass of CDocument or its superclass CDirector
must be created for every type of window the application supports (CDirector does not
have methods for filing or printing). A document object is created whenever “New” or
“Open...” is chosen from the File menu.
Documents are in the chain of command. They manage the communication
between windows, files and menu commands. If a document cannot handle a command, it
passes it up to the application. Methods in the document class are provided to create,
initialize and dispose of documents, open and close windows, read and write data to disk,
access the document data, support printing, support the undoing and redoing of tasks
and update menus.
cDotsDoc is the only document subclass in Dots. Each cDotsDoc object that is
created associates the window and data for a particular game. The data needed to store
the state of a Dots game must contain the following information: whether or not a line is
to be drawn between each adjacent dot in the matrix, the ownership of each completed
square, the player who is to move next.
The inherited document’s initialization method must be overridden. The Dots
override for this method calls the inherited initialization method in order to put the
document in the chain of command and initialize some document variables for filing,
printing, recording moves, and menu updating. The Dots data is then initialized to a new
game state.
The inherited document methods for creating a new file or opening an existing
file must be overridden because they do not do anything. The code for these routines
comes out of the sample programs provided with THINK C. Adaptations were made for
Dots. The main adaptation involves storing the data read in from an opened file into the
document. This is accomplished in the auxiliary method storeData() (Auxiliary means
it is called by other methods within the object in which it is located but not by methods
of other objects. THINK C 4.0 does not support private methods).
Both the new file and open file methods call an auxiliary method,
BuildWindow(), to create a window and the views contained in the window. There are
actually four views in the window. A subclass of CPane is used to display the score and
current player turn. A subclass of CPanorama displays the view of the dot matrix.
These subclasses, cScorePane and cDotsPane, are described in their respective sections.
The two other views in the window are objects of CScrollPane and CSizeBox.
The dot matrix view must be scrollable which is why it is a subclass of
CPanorama. CPanorama has methods that support scrolling. CScrollPane implements a
view with scroll bars to control a panorama. Both CScrollPane and CPanorama are
descendants of CPane which is itself a descendent of CView. They work in tandem to
provide the scrolling capabilities of Dots.
CSizeBox, also a descendant of CPane, is used by CScrollPane to draw a grow icon
in the lower right corner of any pane. By using an icon for the size box, TCL gains
some flexibility in its placement of the size box. The size box no longer has to appear
in the lower right corner of the window. However, in the case of Dots, that’s where it’s
at man.
The code for BuildWindow() is also adapted for Dots from the sample programs.
However, I spent a great deal of time reworking the BuildWindow() code for Dots. This
was in large part caused by my lack of knowledge as to how some of the standard TCL code
worked.
CDecorator is a TCL class that is used to arrange windows on the screen. One of
its methods, PlaceNewWindow(), is used by BuildWindow() to implement window
staggering. Some of the sample programs have BuildWindow() calling
PlaceNewWindow() immediately after the window is created. I followed their example
and got some bad results. The scroll bars for the dot matrix view were being placed